Skip to content

Commit

Permalink
[CrossTU] Fix plist macro expansion if macro in other file.
Browse files Browse the repository at this point in the history
Summary:
When cross TU analysis is used it is possible that a macro expansion
is generated for a macro that is defined (and used) in other than
the main translation unit. To get the expansion for it the source
location in the original source file and original preprocessor
is needed.

Reviewers: martong, xazax.hun, Szelethus, ilya-biryukov

Reviewed By: Szelethus

Subscribers: mgorny, NoQ, ilya-biryukov, rnkovacs, dkrupp, Szelethus, gamesh411, cfe-commits

Tags: #clang

Differential Revision: https://reviews.llvm.org/D64638

llvm-svn: 367006
  • Loading branch information
balazske committed Jul 25, 2019
1 parent c891625 commit aeac909
Show file tree
Hide file tree
Showing 6 changed files with 137 additions and 17 deletions.
1 change: 1 addition & 0 deletions clang/lib/StaticAnalyzer/Core/CMakeLists.txt
Expand Up @@ -53,6 +53,7 @@ add_clang_library(clangStaticAnalyzerCore
clangAnalysis
clangBasic
clangCrossTU
clangFrontend
clangLex
clangRewrite
)
Expand Down
44 changes: 27 additions & 17 deletions clang/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp
Expand Up @@ -15,6 +15,7 @@
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/Version.h"
#include "clang/CrossTU/CrossTranslationUnit.h"
#include "clang/Frontend/ASTUnit.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Lex/TokenConcatenation.h"
#include "clang/Rewrite/Core/HTMLRewrite.h"
Expand Down Expand Up @@ -75,12 +76,14 @@ class PlistPrinter {
const FIDMap& FM;
AnalyzerOptions &AnOpts;
const Preprocessor &PP;
const cross_tu::CrossTranslationUnitContext &CTU;
llvm::SmallVector<const PathDiagnosticMacroPiece *, 0> MacroPieces;

public:
PlistPrinter(const FIDMap& FM, AnalyzerOptions &AnOpts,
const Preprocessor &PP)
: FM(FM), AnOpts(AnOpts), PP(PP) {
const Preprocessor &PP,
const cross_tu::CrossTranslationUnitContext &CTU)
: FM(FM), AnOpts(AnOpts), PP(PP), CTU(CTU) {
}

void ReportDiag(raw_ostream &o, const PathDiagnosticPiece& P) {
Expand Down Expand Up @@ -162,8 +165,8 @@ struct ExpansionInfo {
} // end of anonymous namespace

static void printBugPath(llvm::raw_ostream &o, const FIDMap& FM,
AnalyzerOptions &AnOpts,
const Preprocessor &PP,
AnalyzerOptions &AnOpts, const Preprocessor &PP,
const cross_tu::CrossTranslationUnitContext &CTU,
const PathPieces &Path);

/// Print coverage information to output stream {@code o}.
Expand All @@ -174,8 +177,9 @@ static void printCoverage(const PathDiagnostic *D,
FIDMap &FM,
llvm::raw_fd_ostream &o);

static ExpansionInfo getExpandedMacro(SourceLocation MacroLoc,
const Preprocessor &PP);
static ExpansionInfo
getExpandedMacro(SourceLocation MacroLoc, const Preprocessor &PP,
const cross_tu::CrossTranslationUnitContext &CTU);

//===----------------------------------------------------------------------===//
// Methods of PlistPrinter.
Expand Down Expand Up @@ -349,7 +353,7 @@ void PlistPrinter::ReportMacroExpansions(raw_ostream &o, unsigned indent) {

for (const PathDiagnosticMacroPiece *P : MacroPieces) {
const SourceManager &SM = PP.getSourceManager();
ExpansionInfo EI = getExpandedMacro(P->getLocation().asLocation(), PP);
ExpansionInfo EI = getExpandedMacro(P->getLocation().asLocation(), PP, CTU);

Indent(o, indent) << "<dict>\n";
++indent;
Expand Down Expand Up @@ -471,10 +475,10 @@ static void printCoverage(const PathDiagnostic *D,
}

static void printBugPath(llvm::raw_ostream &o, const FIDMap& FM,
AnalyzerOptions &AnOpts,
const Preprocessor &PP,
AnalyzerOptions &AnOpts, const Preprocessor &PP,
const cross_tu::CrossTranslationUnitContext &CTU,
const PathPieces &Path) {
PlistPrinter Printer(FM, AnOpts, PP);
PlistPrinter Printer(FM, AnOpts, PP, CTU);
assert(std::is_partitioned(
Path.begin(), Path.end(),
[](const std::shared_ptr<PathDiagnosticPiece> &E)
Expand Down Expand Up @@ -619,7 +623,7 @@ void PlistDiagnostics::FlushDiagnosticsImpl(
o << " <dict>\n";

const PathDiagnostic *D = *DI;
printBugPath(o, FM, AnOpts, PP, D->path);
printBugPath(o, FM, AnOpts, PP, CTU, D->path);

// Output the bug type and bug category.
o << " <key>description</key>";
Expand Down Expand Up @@ -872,17 +876,23 @@ static const MacroInfo *getMacroInfoForLocation(const Preprocessor &PP,
// Definitions of helper functions and methods for expanding macros.
//===----------------------------------------------------------------------===//

static ExpansionInfo getExpandedMacro(SourceLocation MacroLoc,
const Preprocessor &PP) {
static ExpansionInfo
getExpandedMacro(SourceLocation MacroLoc, const Preprocessor &PP,
const cross_tu::CrossTranslationUnitContext &CTU) {

const Preprocessor *PPToUse = &PP;
if (auto LocAndUnit = CTU.getImportedFromSourceLocation(MacroLoc)) {
MacroLoc = LocAndUnit->first;
PPToUse = &LocAndUnit->second->getPreprocessor();
}

llvm::SmallString<200> ExpansionBuf;
llvm::raw_svector_ostream OS(ExpansionBuf);
TokenPrinter Printer(OS, PP);
TokenPrinter Printer(OS, *PPToUse);
llvm::SmallPtrSet<IdentifierInfo*, 8> AlreadyProcessedTokens;

std::string MacroName =
getMacroNameAndPrintExpansion(Printer, MacroLoc, PP, MacroArgMap{},
AlreadyProcessedTokens);
std::string MacroName = getMacroNameAndPrintExpansion(
Printer, MacroLoc, *PPToUse, MacroArgMap{}, AlreadyProcessedTokens);
return { MacroName, OS.str() };
}

Expand Down
21 changes: 21 additions & 0 deletions clang/test/Analysis/Inputs/plist-macros-ctu.c
@@ -0,0 +1,21 @@

#include "plist-macros-ctu.h"

#define M *X = (int *)0

void F1(int **X) {
M;
}

#undef M
#define M *Y = (int *)0

void F2(int **Y) {
M;
}

#define M1 *Z = (int *)0

void F3(int **Z) {
M1;
}
4 changes: 4 additions & 0 deletions clang/test/Analysis/Inputs/plist-macros-ctu.h
@@ -0,0 +1,4 @@
#define M_H *A = (int *)0
void F_H(int **A) {
M_H;
}
@@ -0,0 +1,4 @@
c:@F@F1 plist-macros-ctu.c.ast
c:@F@F2 plist-macros-ctu.c.ast
c:@F@F3 plist-macros-ctu.c.ast
c:@F@F_H plist-macros-ctu.c.ast
80 changes: 80 additions & 0 deletions clang/test/Analysis/plist-macros-with-expansion-ctu.c
@@ -0,0 +1,80 @@
// RUN: rm -rf %t && mkdir %t
// RUN: mkdir -p %t/ctudir
// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu \
// RUN: -emit-pch -o %t/ctudir/plist-macros-ctu.c.ast %S/Inputs/plist-macros-ctu.c
// RUN: cp %S/Inputs/plist-macros-with-expansion-ctu.c.externalDefMap.txt %t/ctudir/externalDefMap.txt

// RUN: %clang_analyze_cc1 -analyzer-checker=core \
// RUN: -analyzer-config experimental-enable-naive-ctu-analysis=true \
// RUN: -analyzer-config ctu-dir=%t/ctudir \
// RUN: -analyzer-config expand-macros=true \
// RUN: -analyzer-output=plist-multi-file -o %t.plist -verify %s

// Check the macro expansions from the plist output here, to make the test more
// understandable.
// RUN: FileCheck --input-file=%t.plist %s

extern void F1(int **);
extern void F2(int **);
extern void F3(int **);
extern void F_H(int **);

void test0() {
int *X;
F3(&X);
*X = 1; // expected-warning{{Dereference of null pointer}}
}
// CHECK: <key>name</key><string>M1</string>
// CHECK-NEXT: <key>expansion</key><string>*Z = (int *)0</string>


void test1() {
int *X;
F1(&X);
*X = 1; // expected-warning{{Dereference of null pointer}}
}
// CHECK: <key>name</key><string>M</string>
// CHECK-NEXT: <key>expansion</key><string>*X = (int *)0</string>

void test2() {
int *X;
F2(&X);
*X = 1; // expected-warning{{Dereference of null pointer}}
}
// CHECK: <key>name</key><string>M</string>
// CHECK-NEXT: <key>expansion</key><string>*Y = (int *)0</string>

#define M F1(&X)

void test3() {
int *X;
M;
*X = 1; // expected-warning{{Dereference of null pointer}}
}
// CHECK: <key>name</key><string>M</string>
// CHECK-NEXT: <key>expansion</key><string>F1(&amp;X)</string>
// CHECK: <key>name</key><string>M</string>
// CHECK-NEXT: <key>expansion</key><string>*X = (int *)0</string>

#undef M
#define M F2(&X)

void test4() {
int *X;
M;
*X = 1; // expected-warning{{Dereference of null pointer}}
}

// CHECK: <key>name</key><string>M</string>
// CHECK-NEXT: <key>expansion</key><string>F2(&amp;X)</string>
// CHECK: <key>name</key><string>M</string>
// CHECK-NEXT: <key>expansion</key><string>*Y = (int *)0</string>

void test_h() {
int *X;
F_H(&X);
*X = 1; // expected-warning{{Dereference of null pointer}}
}

// CHECK: <key>name</key><string>M_H</string>
// CHECK-NEXT: <key>expansion</key><string>*A = (int *)0</string>

0 comments on commit aeac909

Please sign in to comment.