Skip to content

Commit ed3b504

Browse files
committed
Translate libclang error codes to exceptions
Do not silence the exceptions.
1 parent 0c2a614 commit ed3b504

11 files changed

+148
-170
lines changed

cpp/ycm/ClangCompleter/ClangCompleter.cpp

+2-36
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616
// along with ycmd. If not, see <http://www.gnu.org/licenses/>.
1717

1818
#include "ClangCompleter.h"
19-
#include "exceptions.h"
2019
#include "Result.h"
2120
#include "Candidate.h"
2221
#include "TranslationUnit.h"
@@ -83,21 +82,15 @@ std::vector< Diagnostic > ClangCompleter::UpdateTranslationUnit(
8382
flags,
8483
translation_unit_created );
8584

86-
if ( !unit )
87-
return std::vector< Diagnostic >();
88-
8985
try {
9086
return unit->Reparse( unsaved_files );
91-
}
92-
93-
catch ( ClangParseError & ) {
87+
} catch ( const ClangParseError & ) {
9488
// If unit->Reparse fails, then the underlying TranslationUnit object is not
9589
// valid anymore and needs to be destroyed and removed from the filename ->
9690
// TU map.
9791
translation_unit_store_.Remove( filename );
92+
throw;
9893
}
99-
100-
return std::vector< Diagnostic >();
10194
}
10295

10396

@@ -112,9 +105,6 @@ ClangCompleter::CandidatesForLocationInFile(
112105
shared_ptr< TranslationUnit > unit =
113106
translation_unit_store_.GetOrCreate( filename, unsaved_files, flags );
114107

115-
if ( !unit )
116-
return std::vector< CompletionData >();
117-
118108
return unit->CandidatesForLocation( line,
119109
column,
120110
unsaved_files );
@@ -132,10 +122,6 @@ Location ClangCompleter::GetDeclarationLocation(
132122
shared_ptr< TranslationUnit > unit =
133123
translation_unit_store_.GetOrCreate( filename, unsaved_files, flags );
134124

135-
if ( !unit ) {
136-
return Location();
137-
}
138-
139125
return unit->GetDeclarationLocation( line, column, unsaved_files, reparse );
140126
}
141127

@@ -151,10 +137,6 @@ Location ClangCompleter::GetDefinitionLocation(
151137
shared_ptr< TranslationUnit > unit =
152138
translation_unit_store_.GetOrCreate( filename, unsaved_files, flags );
153139

154-
if ( !unit ) {
155-
return Location();
156-
}
157-
158140
return unit->GetDefinitionLocation( line, column, unsaved_files, reparse );
159141
}
160142

@@ -170,10 +152,6 @@ std::string ClangCompleter::GetTypeAtLocation(
170152
shared_ptr< TranslationUnit > unit =
171153
translation_unit_store_.GetOrCreate( filename, unsaved_files, flags );
172154

173-
if ( !unit ) {
174-
return "no unit";
175-
}
176-
177155
return unit->GetTypeAtLocation( line, column, unsaved_files, reparse );
178156
}
179157

@@ -189,10 +167,6 @@ std::string ClangCompleter::GetEnclosingFunctionAtLocation(
189167
shared_ptr< TranslationUnit > unit =
190168
translation_unit_store_.GetOrCreate( filename, unsaved_files, flags );
191169

192-
if ( !unit ) {
193-
return "no unit";
194-
}
195-
196170
return unit->GetEnclosingFunctionAtLocation( line,
197171
column,
198172
unsaved_files,
@@ -213,10 +187,6 @@ ClangCompleter::GetFixItsForLocationInFile(
213187
shared_ptr< TranslationUnit > unit =
214188
translation_unit_store_.GetOrCreate( filename, unsaved_files, flags );
215189

216-
if ( !unit ) {
217-
return std::vector< FixIt >();
218-
}
219-
220190
return unit->GetFixItsForLocationInFile( line,
221191
column,
222192
unsaved_files,
@@ -237,10 +207,6 @@ DocumentationData ClangCompleter::GetDocsForLocationInFile(
237207
shared_ptr< TranslationUnit > unit =
238208
translation_unit_store_.GetOrCreate( filename, unsaved_files, flags );
239209

240-
if ( !unit ) {
241-
return DocumentationData();
242-
}
243-
244210
return unit->GetDocsForLocationInFile( line,
245211
column,
246212
unsaved_files,

cpp/ycm/ClangCompleter/ClangUtils.cpp

+25
Original file line numberDiff line numberDiff line change
@@ -43,4 +43,29 @@ std::string ClangVersion() {
4343
return CXStringToString( clang_getClangVersion() );
4444
}
4545

46+
const char *CXErrorCodeToString( CXErrorCode code ) {
47+
switch ( code ) {
48+
case CXError_Success:
49+
return "No error encountered while parsing the translation unit.";
50+
case CXError_Failure:
51+
return "Failed to parse the translation unit.";
52+
case CXError_Crashed:
53+
return "Libclang crashed while parsing the translation unit.";
54+
case CXError_InvalidArguments:
55+
return "Parsing the translation unit with invalid arguments.";
56+
case CXError_ASTReadError:
57+
return "An AST deserialization error occurred "
58+
"while parsing the translation unit.";
59+
}
60+
return "Unknown error while parsing the translation unit.";
61+
}
62+
63+
ClangParseError::ClangParseError( const char *what_arg )
64+
: std::runtime_error( what_arg ) {
65+
};
66+
67+
ClangParseError::ClangParseError( CXErrorCode code )
68+
: ClangParseError( CXErrorCodeToString( code ) ) {
69+
};
70+
4671
} // namespace YouCompleteMe

cpp/ycm/ClangCompleter/ClangUtils.h

+11
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#define CLANGUTILS_H_9MVHQLJS
2020

2121
#include <clang-c/Index.h>
22+
#include <stdexcept>
2223
#include <string>
2324

2425
namespace YouCompleteMe {
@@ -37,6 +38,16 @@ std::string CXFileToFilepath( CXFile file );
3738

3839
std::string ClangVersion();
3940

41+
const char *CXErrorCodeToString( CXErrorCode code );
42+
43+
/**
44+
* Thrown when libclang fails to parse (or reparse) the translation unit.
45+
*/
46+
struct ClangParseError : std::runtime_error {
47+
ClangParseError( const char *what_arg );
48+
ClangParseError( CXErrorCode code );
49+
};
50+
4051
} // namespace YouCompleteMe
4152

4253
#endif /* end of include guard: CLANGUTILS_H_9MVHQLJS */

cpp/ycm/ClangCompleter/TranslationUnit.cpp

+21-20
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717

1818
#include "TranslationUnit.h"
1919
#include "CompletionData.h"
20-
#include "exceptions.h"
2120
#include "ClangUtils.h"
2221
#include "ClangHelpers.h"
2322

@@ -94,18 +93,17 @@ TranslationUnit::TranslationUnit(
9493
? &cxunsaved_files[ 0 ] : NULL;
9594

9695
// Actually parse the translation unit.
97-
CXErrorCode result = clang_parseTranslationUnit2FullArgv(
98-
clang_index,
99-
filename.c_str(),
100-
&pointer_flags[ 0 ],
101-
pointer_flags.size(),
102-
const_cast<CXUnsavedFile *>( unsaved ),
103-
cxunsaved_files.size(),
104-
EditingOptions(),
105-
&clang_translation_unit_ );
106-
107-
if ( result != CXError_Success )
108-
throw( ClangParseError() );
96+
CXErrorCode failure = clang_parseTranslationUnit2FullArgv(
97+
clang_index,
98+
filename.c_str(),
99+
&pointer_flags[ 0 ],
100+
pointer_flags.size(),
101+
const_cast<CXUnsavedFile *>( unsaved ),
102+
cxunsaved_files.size(),
103+
EditingOptions(),
104+
&clang_translation_unit_ );
105+
if ( failure != CXError_Success )
106+
throw ClangParseError( failure );
109107
}
110108

111109

@@ -352,7 +350,7 @@ void TranslationUnit::Reparse(
352350
// param though.
353351
void TranslationUnit::Reparse( std::vector< CXUnsavedFile > &unsaved_files,
354352
size_t parse_options ) {
355-
int failure = 0;
353+
CXErrorCode failure;
356354
{
357355
unique_lock< mutex > lock( clang_access_mutex_ );
358356

@@ -362,15 +360,18 @@ void TranslationUnit::Reparse( std::vector< CXUnsavedFile > &unsaved_files,
362360
CXUnsavedFile *unsaved = unsaved_files.size() > 0
363361
? &unsaved_files[ 0 ] : NULL;
364362

365-
failure = clang_reparseTranslationUnit( clang_translation_unit_,
366-
unsaved_files.size(),
367-
unsaved,
368-
parse_options );
363+
// This function should technically return a CXErrorCode enum but return an
364+
// int instead.
365+
failure = static_cast< CXErrorCode >(
366+
clang_reparseTranslationUnit( clang_translation_unit_,
367+
unsaved_files.size(),
368+
unsaved,
369+
parse_options ) );
369370
}
370371

371-
if ( failure ) {
372+
if ( failure != CXError_Success ) {
372373
Destroy();
373-
throw( ClangParseError() );
374+
throw ClangParseError( failure );
374375
}
375376

376377
UpdateLatestDiagnostics();

cpp/ycm/ClangCompleter/TranslationUnitStore.cpp

+2-3
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818
#include "TranslationUnitStore.h"
1919
#include "TranslationUnit.h"
2020
#include "Utils.h"
21-
#include "exceptions.h"
2221

2322
#include <functional>
2423

@@ -106,9 +105,9 @@ shared_ptr< TranslationUnit > TranslationUnitStore::GetOrCreate(
106105
unsaved_files,
107106
flags,
108107
clang_index_ );
109-
} catch ( ClangParseError & ) {
108+
} catch ( const ClangParseError & ) {
110109
Remove( filename );
111-
return unit;
110+
throw;
112111
}
113112

114113
{

cpp/ycm/PythonSupport.h

+36
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,42 @@ YCM_DLL_EXPORT boost::python::list FilterAndSortCandidates(
4141
/// a string. Supports newstr and newbytes from python-future on Python 2.
4242
std::string GetUtf8String( const boost::python::object &value );
4343

44+
/// Expose the C++ exception |CppException| as a Python exception inheriting
45+
/// from the base exception |base_exception| (default being Exception) with the
46+
/// fully qualified name <module>.|name| where <module> is the current
47+
/// Boost.Python module. |CppException| must define a what() method (easiest way
48+
/// is to derive it from std::runtime_error). This templated class should be
49+
/// instantiated inside the BOOST_PYTHON_MODULE macro.
50+
template< typename CppException >
51+
class PythonException {
52+
public:
53+
54+
PythonException( const char* name,
55+
PyObject* base_exception = PyExc_Exception ) {
56+
std::string module_name = boost::python::extract< std::string >(
57+
boost::python::scope().attr( "__name__" ) );
58+
std::string fully_qualified_name = module_name + "." + name;
59+
// PyErr_NewException does not modify the exception name so it's safe to
60+
// cast away constness.
61+
char *raw_name = const_cast< char * >( fully_qualified_name.c_str() );
62+
python_exception_ = PyErr_NewException( raw_name, base_exception, NULL );
63+
64+
// Add the Python exception to the current Boost.Python module.
65+
boost::python::scope().attr( name ) = boost::python::handle<>(
66+
boost::python::borrowed( python_exception_ ) );
67+
68+
boost::python::register_exception_translator< CppException >( *this );
69+
};
70+
71+
void operator() ( const CppException &cpp_exception ) const {
72+
PyErr_SetString( python_exception_, cpp_exception.what() );
73+
}
74+
75+
private:
76+
PyObject* python_exception_;
77+
78+
};
79+
4480
} // namespace YouCompleteMe
4581

4682
#endif /* end of include guard: PYTHONSUPPORT_H_KWGFEX0V */

cpp/ycm/exceptions.h

-40
This file was deleted.

cpp/ycm/tests/ClangCompleter/ClangCompleter_test.cpp

-55
Original file line numberDiff line numberDiff line change
@@ -204,59 +204,4 @@ TEST( ClangCompleterTest, GetDocString ) {
204204
}
205205
}
206206

207-
208-
TEST( ClangCompleterTest, NoTranslationUnit ) {
209-
ClangCompleter completer;
210-
211-
const std::string filename;
212-
const std::vector< UnsavedFile > unsaved_files;
213-
const std::vector< std::string > flags;
214-
215-
EXPECT_EQ( std::vector< Diagnostic >(),
216-
completer.UpdateTranslationUnit( filename, unsaved_files, flags) );
217-
218-
EXPECT_EQ( std::vector< CompletionData >(),
219-
completer.CandidatesForLocationInFile( filename,
220-
1,
221-
1,
222-
unsaved_files,
223-
flags ) );
224-
225-
EXPECT_EQ( Location(), completer.GetDeclarationLocation( filename,
226-
1,
227-
1,
228-
unsaved_files,
229-
flags ) );
230-
EXPECT_EQ( Location(), completer.GetDefinitionLocation( filename,
231-
1,
232-
1,
233-
unsaved_files,
234-
flags ) );
235-
EXPECT_EQ( std::string( "no unit" ),
236-
completer.GetTypeAtLocation( filename,
237-
1,
238-
1,
239-
unsaved_files,
240-
flags ) );
241-
EXPECT_EQ( std::string( "no unit" ),
242-
completer.GetEnclosingFunctionAtLocation( filename,
243-
1,
244-
1,
245-
unsaved_files,
246-
flags ) );
247-
EXPECT_EQ( std::vector< FixIt >(),
248-
completer.GetFixItsForLocationInFile( filename,
249-
1,
250-
1,
251-
unsaved_files,
252-
flags ) );
253-
254-
EXPECT_EQ( DocumentationData(),
255-
completer.GetDocsForLocationInFile( filename,
256-
1,
257-
1,
258-
unsaved_files,
259-
flags ) );
260-
}
261-
262207
} // namespace YouCompleteMe

0 commit comments

Comments
 (0)