forked from OSchip/llvm-project
Added new feature for checking macro and preprocessor conditional consistency.
llvm-svn: 187228
This commit is contained in:
parent
318f09fda7
commit
1e0101461e
|
@ -7,6 +7,7 @@ set(LLVM_LINK_COMPONENTS
|
|||
|
||||
add_clang_executable(modularize
|
||||
Modularize.cpp
|
||||
PreprocessorTracker.cpp
|
||||
)
|
||||
|
||||
target_link_libraries(modularize
|
||||
|
|
|
@ -90,10 +90,12 @@
|
|||
#include <iterator>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "PreprocessorTracker.h"
|
||||
|
||||
using namespace clang::tooling;
|
||||
using namespace clang;
|
||||
using namespace llvm;
|
||||
using namespace Modularize;
|
||||
|
||||
// Option to specify a file name for a list of header files to check.
|
||||
cl::opt<std::string>
|
||||
|
@ -382,8 +384,14 @@ private:
|
|||
|
||||
class CollectEntitiesConsumer : public ASTConsumer {
|
||||
public:
|
||||
CollectEntitiesConsumer(EntityMap &Entities, Preprocessor &PP)
|
||||
: Entities(Entities), PP(PP) {}
|
||||
CollectEntitiesConsumer(EntityMap &Entities,
|
||||
PreprocessorTracker &preprocessorTracker,
|
||||
Preprocessor &PP, StringRef InFile)
|
||||
: Entities(Entities), PPTracker(preprocessorTracker), PP(PP) {
|
||||
PPTracker.handlePreprocessorEntry(PP, InFile);
|
||||
}
|
||||
|
||||
~CollectEntitiesConsumer() { PPTracker.handlePreprocessorExit(); }
|
||||
|
||||
virtual void HandleTranslationUnit(ASTContext &Ctx) {
|
||||
SourceManager &SM = Ctx.getSourceManager();
|
||||
|
@ -409,33 +417,41 @@ public:
|
|||
|
||||
private:
|
||||
EntityMap &Entities;
|
||||
PreprocessorTracker &PPTracker;
|
||||
Preprocessor &PP;
|
||||
};
|
||||
|
||||
class CollectEntitiesAction : public SyntaxOnlyAction {
|
||||
public:
|
||||
CollectEntitiesAction(EntityMap &Entities) : Entities(Entities) {}
|
||||
CollectEntitiesAction(EntityMap &Entities,
|
||||
PreprocessorTracker &preprocessorTracker)
|
||||
: Entities(Entities), PPTracker(preprocessorTracker) {}
|
||||
|
||||
protected:
|
||||
virtual clang::ASTConsumer *CreateASTConsumer(CompilerInstance &CI,
|
||||
StringRef InFile) {
|
||||
return new CollectEntitiesConsumer(Entities, CI.getPreprocessor());
|
||||
return new CollectEntitiesConsumer(Entities, PPTracker,
|
||||
CI.getPreprocessor(), InFile);
|
||||
}
|
||||
|
||||
private:
|
||||
EntityMap &Entities;
|
||||
PreprocessorTracker &PPTracker;
|
||||
};
|
||||
|
||||
class ModularizeFrontendActionFactory : public FrontendActionFactory {
|
||||
public:
|
||||
ModularizeFrontendActionFactory(EntityMap &Entities) : Entities(Entities) {}
|
||||
ModularizeFrontendActionFactory(EntityMap &Entities,
|
||||
PreprocessorTracker &preprocessorTracker)
|
||||
: Entities(Entities), PPTracker(preprocessorTracker) {}
|
||||
|
||||
virtual CollectEntitiesAction *create() {
|
||||
return new CollectEntitiesAction(Entities);
|
||||
return new CollectEntitiesAction(Entities, PPTracker);
|
||||
}
|
||||
|
||||
private:
|
||||
EntityMap &Entities;
|
||||
PreprocessorTracker &PPTracker;
|
||||
};
|
||||
|
||||
int main(int argc, const char **argv) {
|
||||
|
@ -464,10 +480,14 @@ int main(int argc, const char **argv) {
|
|||
Compilations.reset(
|
||||
new FixedCompilationDatabase(Twine(PathBuf), CC1Arguments));
|
||||
|
||||
// Create preprocessor tracker, to watch for macro and conditional problems.
|
||||
OwningPtr<PreprocessorTracker> PPTracker(PreprocessorTracker::create());
|
||||
|
||||
// Parse all of the headers, detecting duplicates.
|
||||
EntityMap Entities;
|
||||
ClangTool Tool(*Compilations, Headers);
|
||||
int HadErrors = Tool.run(new ModularizeFrontendActionFactory(Entities));
|
||||
int HadErrors =
|
||||
Tool.run(new ModularizeFrontendActionFactory(Entities, *PPTracker));
|
||||
|
||||
// Create a place to save duplicate entity locations, separate bins per kind.
|
||||
typedef SmallVector<Location, 8> LocationArray;
|
||||
|
@ -515,6 +535,16 @@ int main(int argc, const char **argv) {
|
|||
}
|
||||
}
|
||||
|
||||
// Complain about macro instance in header files that differ based on how
|
||||
// they are included.
|
||||
if (PPTracker->reportInconsistentMacros(errs()))
|
||||
HadErrors = 1;
|
||||
|
||||
// Complain about preprocessor conditional directives in header files that
|
||||
// differ based on how they are included.
|
||||
if (PPTracker->reportInconsistentConditionals(errs()))
|
||||
HadErrors = 1;
|
||||
|
||||
// Complain about any headers that have contents that differ based on how
|
||||
// they are included.
|
||||
// FIXME: Could we provide information about which preprocessor conditionals
|
||||
|
@ -530,7 +560,7 @@ int main(int argc, const char **argv) {
|
|||
|
||||
HadErrors = 1;
|
||||
errs() << "error: header '" << H->first->getName()
|
||||
<< "' has different contents depending on how it was included\n";
|
||||
<< "' has different contents depending on how it was included.\n";
|
||||
for (unsigned I = 0, N = H->second.size(); I != N; ++I) {
|
||||
errs() << "note: '" << H->second[I].Name << "' in "
|
||||
<< H->second[I].Loc.File->getName() << " at "
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,53 @@
|
|||
//===- PreprocessorTracker.h - Tracks preprocessor activities -*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===--------------------------------------------------------------------===//
|
||||
///
|
||||
/// \file
|
||||
/// \brief Track preprocessor activities for modularize.
|
||||
///
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
||||
#ifndef MODULARIZE_PREPROCESSOR_TRACKER_H
|
||||
#define MODULARIZE_PREPROCESSOR_TRACKER_H
|
||||
|
||||
#include "clang/Lex/Preprocessor.h"
|
||||
|
||||
namespace Modularize {
|
||||
|
||||
// Preprocessor tracker for modularize.
|
||||
//
|
||||
// This class stores information about all the headers processed in the
|
||||
// course of running modularize.
|
||||
class PreprocessorTracker {
|
||||
public:
|
||||
virtual ~PreprocessorTracker();
|
||||
|
||||
// Handle entering a preprocessing session.
|
||||
// (Called after a Preprocessor object is created, but before preprocessing.)
|
||||
virtual void handlePreprocessorEntry(clang::Preprocessor &PP,
|
||||
llvm::StringRef RootHeaderFile) = 0;
|
||||
// Handle exiting a preprocessing session.
|
||||
// (Called after preprocessing is complete, but before the Preprocessor
|
||||
// object is destroyed.)
|
||||
virtual void handlePreprocessorExit() = 0;
|
||||
|
||||
// Report on inconsistent macro instances.
|
||||
// Returns true if any mismatches.
|
||||
virtual bool reportInconsistentMacros(llvm::raw_ostream &OS) = 0;
|
||||
|
||||
// Report on inconsistent conditional directive instances.
|
||||
// Returns true if any mismatches.
|
||||
virtual bool reportInconsistentConditionals(llvm::raw_ostream &OS) = 0;
|
||||
|
||||
// Create instance of PreprocessorTracker.
|
||||
static PreprocessorTracker *create();
|
||||
};
|
||||
|
||||
} // end namespace Modularize
|
||||
|
||||
#endif
|
|
@ -1,11 +1,18 @@
|
|||
// Set up so TypeInt only defined during InconsistentHeader1.h include.
|
||||
#ifdef SYMBOL1
|
||||
#define SYMBOL 1
|
||||
#define FUNC_STYLE(a, b) a || b
|
||||
#endif
|
||||
#ifdef SYMBOL2
|
||||
#define SYMBOL 2
|
||||
#define FUNC_STYLE(a, b) a &&b
|
||||
#endif
|
||||
|
||||
#if SYMBOL == 1
|
||||
typedef int TypeInt;
|
||||
#endif
|
||||
|
||||
int var = FUNC_STYLE(1, 0);
|
||||
|
||||
#if defined(SYMBOL1)
|
||||
#endif
|
||||
|
|
|
@ -4,9 +4,105 @@ Inputs/InconsistentHeader1.h
|
|||
Inputs/InconsistentHeader2.h
|
||||
|
||||
# CHECK: error: macro 'SYMBOL' defined at multiple locations:
|
||||
# CHECK-NEXT: {{.*}}{{[/\\]}}Inputs{{[/\\]}}InconsistentSubHeader.h:3:9
|
||||
# CHECK-NEXT: {{.*}}{{[/\\]}}Inputs{{[/\\]}}InconsistentSubHeader.h:6:9
|
||||
# CHECK-NEXT: error: header '{{.*}}{{[/\\]}}Inputs{{[/\\]}}InconsistentSubHeader.h' has different contents depending on how it was included
|
||||
# CHECK-NEXT: {{.*}}{{[/\\]}}Inputs{{[/\\]}}InconsistentSubHeader.h:3:9
|
||||
# CHECK-NEXT: {{.*}}{{[/\\]}}Inputs{{[/\\]}}InconsistentSubHeader.h:7:9
|
||||
# CHECK-NEXT: error: macro 'FUNC_STYLE' defined at multiple locations:
|
||||
# CHECK-NEXT: {{.*}}{{[/\\]}}Inputs{{[/\\]}}InconsistentSubHeader.h:4:9
|
||||
# CHECK-NEXT: {{.*}}{{[/\\]}}Inputs{{[/\\]}}InconsistentSubHeader.h:8:9
|
||||
# CHECK-NEXT: {{.*}}{{[/\\]}}Inputs{{[/\\]}}InconsistentSubHeader.h:15:11:
|
||||
# CHECK-NEXT: int var = FUNC_STYLE(1, 0);
|
||||
# CHECK-NEXT: ^
|
||||
# CHECK-NEXT: error: Macro instance 'FUNC_STYLE(1, 0);' has different values in this header, depending on how it was included.
|
||||
# CHECK-NEXT: 'FUNC_STYLE(1, 0);' expanded to: '1||0' with respect to these inclusion paths:
|
||||
# CHECK-NEXT: {{.*}}{{[/\\]}}Inputs{{[/\\]}}InconsistentHeader1.h
|
||||
# CHECK-NEXT: {{.*}}{{[/\\]}}Inputs{{[/\\]}}InconsistentSubHeader.h
|
||||
# CHECK-NEXT: {{.*}}{{[/\\]}}Inputs{{[/\\]}}InconsistentSubHeader.h:4:9:
|
||||
# CHECK-NEXT: #define FUNC_STYLE(a, b) a || b
|
||||
# CHECK-NEXT: ^
|
||||
# CHECK-NEXT: Macro defined here.
|
||||
# CHECK-NEXT: 'FUNC_STYLE(1, 0);' expanded to: '1&&0' with respect to these inclusion paths:
|
||||
# CHECK-NEXT: {{.*}}{{[/\\]}}Inputs{{[/\\]}}InconsistentHeader2.h
|
||||
# CHECK-NEXT: {{.*}}{{[/\\]}}Inputs{{[/\\]}}InconsistentSubHeader.h
|
||||
# CHECK-NEXT: {{.*}}{{[/\\]}}Inputs{{[/\\]}}InconsistentSubHeader.h:8:9:
|
||||
# CHECK-NEXT: #define FUNC_STYLE(a, b) a &&b
|
||||
# CHECK-NEXT: ^
|
||||
# CHECK-NEXT: Macro defined here.
|
||||
# CHECK-NEXT: {{.*}}{{[/\\]}}Inputs{{[/\\]}}InconsistentSubHeader.h:11:5:
|
||||
# CHECK-NEXT: #if SYMBOL == 1
|
||||
# CHECK-NEXT: ^
|
||||
# CHECK-NEXT: error: Macro instance 'SYMBOL' has different values in this header, depending on how it was included.
|
||||
# CHECK-NEXT: 'SYMBOL' expanded to: '1' with respect to these inclusion paths:
|
||||
# CHECK-NEXT: {{.*}}{{[/\\]}}Inputs{{[/\\]}}InconsistentHeader1.h
|
||||
# CHECK-NEXT: {{.*}}{{[/\\]}}Inputs{{[/\\]}}InconsistentSubHeader.h
|
||||
# CHECK-NEXT: {{.*}}{{[/\\]}}Inputs{{[/\\]}}InconsistentSubHeader.h:3:9:
|
||||
# CHECK-NEXT: #define SYMBOL 1
|
||||
# CHECK-NEXT: ^
|
||||
# CHECK-NEXT: Macro defined here.
|
||||
# CHECK-NEXT: 'SYMBOL' expanded to: '2' with respect to these inclusion paths:
|
||||
# CHECK-NEXT: {{.*}}{{[/\\]}}Inputs{{[/\\]}}InconsistentHeader2.h
|
||||
# CHECK-NEXT: {{.*}}{{[/\\]}}Inputs{{[/\\]}}InconsistentSubHeader.h
|
||||
# CHECK-NEXT: {{.*}}{{[/\\]}}Inputs{{[/\\]}}InconsistentSubHeader.h:7:9:
|
||||
# CHECK-NEXT: #define SYMBOL 2
|
||||
# CHECK-NEXT: ^
|
||||
# CHECK-NEXT: Macro defined here.
|
||||
# CHECK-NEXT: {{.*}}{{[/\\]}}Inputs{{[/\\]}}InconsistentSubHeader.h:17:5:
|
||||
# CHECK-NEXT: #if defined(SYMBOL1)
|
||||
# CHECK-NEXT: ^
|
||||
# CHECK-NEXT: error: Macro instance 'defined(SYMBOL1)' has different values in this header, depending on how it was included.
|
||||
# CHECK-NEXT: 'defined(SYMBOL1)' expanded to: 'true' with respect to these inclusion paths:
|
||||
# CHECK-NEXT: {{.*}}{{[/\\]}}Inputs{{[/\\]}}InconsistentHeader1.h
|
||||
# CHECK-NEXT: {{.*}}{{[/\\]}}Inputs{{[/\\]}}InconsistentSubHeader.h
|
||||
# CHECK-NEXT: {{.*}}{{[/\\]}}Inputs{{[/\\]}}InconsistentHeader1.h:3:9:
|
||||
# CHECK-NEXT: #define SYMBOL1 1
|
||||
# CHECK-NEXT: ^
|
||||
# CHECK-NEXT: Macro defined here.
|
||||
# CHECK-NEXT: 'defined(SYMBOL1)' expanded to: 'false' with respect to these inclusion paths:
|
||||
# CHECK-NEXT: {{.*}}{{[/\\]}}Inputs{{[/\\]}}InconsistentHeader2.h
|
||||
# CHECK-NEXT: {{.*}}{{[/\\]}}Inputs{{[/\\]}}InconsistentSubHeader.h
|
||||
# CHECK-NEXT: (no macro definition)
|
||||
# CHECK-NEXT: {{.*}}{{[/\\]}}Inputs{{[/\\]}}InconsistentSubHeader.h:11:2
|
||||
# CHECK-NEXT: #if SYMBOL == 1
|
||||
# CHECK-NEXT: ^
|
||||
# CHECK-NEXT: error: Conditional expression instance 'SYMBOL == 1' has different values in this header, depending on how it was included.
|
||||
# CHECK-NEXT: 'SYMBOL == 1' expanded to: 'true' with respect to these inclusion paths:
|
||||
# CHECK-NEXT: {{.*}}{{[/\\]}}Inputs{{[/\\]}}InconsistentHeader1.h
|
||||
# CHECK-NEXT: {{.*}}{{[/\\]}}Inputs{{[/\\]}}InconsistentSubHeader.h
|
||||
# CHECK-NEXT: 'SYMBOL == 1' expanded to: 'false' with respect to these inclusion paths:
|
||||
# CHECK-NEXT: {{.*}}{{[/\\]}}Inputs{{[/\\]}}InconsistentHeader2.h
|
||||
# CHECK-NEXT: {{.*}}{{[/\\]}}Inputs{{[/\\]}}InconsistentSubHeader.h
|
||||
# CHECK-NEXT: {{.*}}{{[/\\]}}Inputs{{[/\\]}}InconsistentSubHeader.h:2:2
|
||||
# CHECK-NEXT: #ifdef SYMBOL1
|
||||
# CHECK-NEXT: ^
|
||||
# CHECK-NEXT: error: Conditional expression instance 'SYMBOL1' has different values in this header, depending on how it was included.
|
||||
# CHECK-NEXT: 'SYMBOL1' expanded to: 'true' with respect to these inclusion paths:
|
||||
# CHECK-NEXT: {{.*}}{{[/\\]}}Inputs{{[/\\]}}InconsistentHeader1.h
|
||||
# CHECK-NEXT: {{.*}}{{[/\\]}}Inputs{{[/\\]}}InconsistentSubHeader.h
|
||||
# CHECK-NEXT: 'SYMBOL1' expanded to: 'false' with respect to these inclusion paths:
|
||||
# CHECK-NEXT: {{.*}}{{[/\\]}}Inputs{{[/\\]}}InconsistentHeader2.h
|
||||
# CHECK-NEXT: {{.*}}{{[/\\]}}Inputs{{[/\\]}}InconsistentSubHeader.h
|
||||
# CHECK-NEXT: {{.*}}{{[/\\]}}Inputs{{[/\\]}}InconsistentSubHeader.h:6:2
|
||||
# CHECK-NEXT: #ifdef SYMBOL2
|
||||
# CHECK-NEXT: ^
|
||||
# CHECK-NEXT: error: Conditional expression instance 'SYMBOL2' has different values in this header, depending on how it was included.
|
||||
# CHECK-NEXT: 'SYMBOL2' expanded to: 'false' with respect to these inclusion paths:
|
||||
# CHECK-NEXT: {{.*}}{{[/\\]}}Inputs{{[/\\]}}InconsistentHeader1.h
|
||||
# CHECK-NEXT: {{.*}}{{[/\\]}}Inputs{{[/\\]}}InconsistentSubHeader.h
|
||||
# CHECK-NEXT: 'SYMBOL2' expanded to: 'true' with respect to these inclusion paths:
|
||||
# CHECK-NEXT: {{.*}}{{[/\\]}}Inputs{{[/\\]}}InconsistentHeader2.h
|
||||
# CHECK-NEXT: {{.*}}{{[/\\]}}Inputs{{[/\\]}}InconsistentSubHeader.h
|
||||
# CHECK-NEXT: {{.*}}{{[/\\]}}Inputs{{[/\\]}}InconsistentSubHeader.h:17:2
|
||||
# CHECK-NEXT: #if defined(SYMBOL1)
|
||||
# CHECK-NEXT: ^
|
||||
# CHECK-NEXT: error: Conditional expression instance 'defined(SYMBOL1)' has different values in this header, depending on how it was included.
|
||||
# CHECK-NEXT: 'defined(SYMBOL1)' expanded to: 'true' with respect to these inclusion paths:
|
||||
# CHECK-NEXT: {{.*}}{{[/\\]}}Inputs{{[/\\]}}InconsistentHeader1.h
|
||||
# CHECK-NEXT: {{.*}}{{[/\\]}}Inputs{{[/\\]}}InconsistentSubHeader.h
|
||||
# CHECK-NEXT: 'defined(SYMBOL1)' expanded to: 'false' with respect to these inclusion paths:
|
||||
# CHECK-NEXT: {{.*}}{{[/\\]}}Inputs{{[/\\]}}InconsistentHeader2.h
|
||||
# CHECK-NEXT: {{.*}}{{[/\\]}}Inputs{{[/\\]}}InconsistentSubHeader.h
|
||||
# CHECK-NEXT: error: header '{{.*}}{{[/\\]}}Inputs{{[/\\]}}InconsistentSubHeader.h' has different contents depending on how it was included.
|
||||
# CHECK-NEXT: note: 'SYMBOL' in {{.*}}{{[/\\]}}Inputs{{[/\\]}}InconsistentSubHeader.h at 3:9 not always provided
|
||||
# CHECK-NEXT: note: 'SYMBOL' in {{.*}}{{[/\\]}}Inputs{{[/\\]}}InconsistentSubHeader.h at 6:9 not always provided
|
||||
# CHECK-NEXT: note: 'TypeInt' in {{.*}}{{[/\\]}}Inputs{{[/\\]}}InconsistentSubHeader.h at 10:13 not always provided
|
||||
# CHECK-NEXT: note: 'FUNC_STYLE' in {{.*}}{{[/\\]}}Inputs{{[/\\]}}InconsistentSubHeader.h at 4:9 not always provided
|
||||
# CHECK-NEXT: note: 'SYMBOL' in {{.*}}{{[/\\]}}Inputs{{[/\\]}}InconsistentSubHeader.h at 7:9 not always provided
|
||||
# CHECK-NEXT: note: 'FUNC_STYLE' in {{.*}}{{[/\\]}}Inputs{{[/\\]}}InconsistentSubHeader.h at 8:9 not always provided
|
||||
# CHECK-NEXT: note: 'TypeInt' in {{.*}}{{[/\\]}}Inputs{{[/\\]}}InconsistentSubHeader.h at 12:13 not always provided
|
||||
|
|
Loading…
Reference in New Issue