~ubuntu-branches/ubuntu/trusty/llvm-toolchain-snapshot/trusty-201310232150

« back to all changes in this revision

Viewing changes to clang-tools-extra/cpp11-migrate/UseNullptr/NullptrActions.cpp

  • Committer: Package Import Robot
  • Author(s): Sylvestre Ledru
  • Date: 2013-05-27 15:01:57 UTC
  • mfrom: (0.10.1) (0.9.1) (0.8.1) (0.7.1) (0.6.1) (0.5.2)
  • Revision ID: package-import@ubuntu.com-20130527150157-tdkrsjpuvht7v0qx
Tags: 1:3.4~svn182733-1~exp1
* New snapshot release (3.4 release)
* Add a symlink of libLLVM-3.4.so.1 to usr/lib/llvm-3.4/lib/libLLVM-3.4.so
    to fix make the llvm-config-3.4 --libdir work (Closes: #708677)
  * Various packages rename to allow co installations:
    * libclang1 => libclang1-3.4
    * libclang1-dbg => libclang1-3.4-dbg
    * libclang-dev => libclang-3.4-dev
    * libclang-common-dev => libclang-common-3.4-dev

Show diffs side-by-side

added added

removed removed

Lines of Context:
36
36
                                       "macro names that behave like NULL"),
37
37
    llvm::cl::init(""));
38
38
 
 
39
bool isReplaceableRange(SourceLocation StartLoc, SourceLocation EndLoc,
 
40
                        const SourceManager &SM) {
 
41
  return SM.isFromSameFile(StartLoc, EndLoc) && SM.isFromMainFile(StartLoc);
 
42
}
 
43
 
39
44
/// \brief Replaces the provided range with the text "nullptr", but only if
40
45
/// the start and end location are both in main file.
41
46
/// Returns true if and only if a replacement was made.
42
 
bool ReplaceWithNullptr(tooling::Replacements &Replace, SourceManager &SM,
 
47
void ReplaceWithNullptr(tooling::Replacements &Replace, SourceManager &SM,
43
48
                        SourceLocation StartLoc, SourceLocation EndLoc) {
44
 
  if (SM.isFromSameFile(StartLoc, EndLoc) && SM.isFromMainFile(StartLoc)) {
45
 
    CharSourceRange Range(SourceRange(StartLoc, EndLoc), true);
46
 
    // Add a space if nullptr follows an alphanumeric character. This happens
47
 
    // whenever there is an c-style explicit cast to nullptr not surrounded by
48
 
    // parentheses and right beside a return statement.
49
 
    SourceLocation PreviousLocation = StartLoc.getLocWithOffset(-1);
50
 
    if (isAlphanumeric(*FullSourceLoc(PreviousLocation, SM).getCharacterData()))
51
 
      Replace.insert(tooling::Replacement(SM, Range, " nullptr"));
52
 
    else
53
 
      Replace.insert(tooling::Replacement(SM, Range, "nullptr"));
54
 
    return true;
55
 
  } else
56
 
    return false;
 
49
  CharSourceRange Range(SourceRange(StartLoc, EndLoc), true);
 
50
  // Add a space if nullptr follows an alphanumeric character. This happens
 
51
  // whenever there is an c-style explicit cast to nullptr not surrounded by
 
52
  // parentheses and right beside a return statement.
 
53
  SourceLocation PreviousLocation = StartLoc.getLocWithOffset(-1);
 
54
  if (isAlphanumeric(*FullSourceLoc(PreviousLocation, SM).getCharacterData()))
 
55
    Replace.insert(tooling::Replacement(SM, Range, " nullptr"));
 
56
  else
 
57
    Replace.insert(tooling::Replacement(SM, Range, "nullptr"));
57
58
}
58
59
 
59
60
/// \brief Returns the name of the outermost macro.
75
76
 
76
77
  return clang::Lexer::getImmediateMacroName(OutermostMacroLoc, SM, LO);
77
78
}
78
 
}
 
79
 
 
80
/// \brief RecursiveASTVisitor for ensuring all nodes rooted at a given AST
 
81
/// subtree that have file-level source locations corresponding to a macro
 
82
/// argument have implicit NullTo(Member)Pointer nodes as ancestors.
 
83
class MacroArgUsageVisitor : public RecursiveASTVisitor<MacroArgUsageVisitor> {
 
84
public:
 
85
  MacroArgUsageVisitor(SourceLocation CastLoc, const SourceManager &SM)
 
86
      : CastLoc(CastLoc), SM(SM), Visited(false), CastFound(false),
 
87
        InvalidFound(false) {
 
88
    assert(CastLoc.isFileID());
 
89
  }
 
90
 
 
91
  bool TraverseStmt(Stmt *S) {
 
92
    bool VisitedPreviously = Visited;
 
93
 
 
94
    if (!RecursiveASTVisitor<MacroArgUsageVisitor>::TraverseStmt(S))
 
95
      return false;
 
96
 
 
97
    // The point at which VisitedPreviously is false and Visited is true is the
 
98
    // root of a subtree containing nodes whose locations match CastLoc. It's
 
99
    // at this point we test that the Implicit NullTo(Member)Pointer cast was
 
100
    // found or not.
 
101
    if (!VisitedPreviously) {
 
102
      if (Visited && !CastFound) {
 
103
        // Found nodes with matching SourceLocations but didn't come across a
 
104
        // cast. This is an invalid macro arg use. Can stop traversal
 
105
        // completely now.
 
106
        InvalidFound = true;
 
107
        return false;
 
108
      }
 
109
      // Reset state as we unwind back up the tree.
 
110
      CastFound = false;
 
111
      Visited = false;
 
112
    }
 
113
    return true;
 
114
  }
 
115
 
 
116
  bool VisitStmt(Stmt *S) {
 
117
    if (SM.getFileLoc(S->getLocStart()) != CastLoc)
 
118
      return true;
 
119
    Visited = true;
 
120
 
 
121
    const ImplicitCastExpr *Cast = dyn_cast<ImplicitCastExpr>(S);
 
122
    if (Cast && (Cast->getCastKind() == CK_NullToPointer ||
 
123
                 Cast->getCastKind() == CK_NullToMemberPointer))
 
124
      CastFound = true;
 
125
 
 
126
    return true;
 
127
  }
 
128
 
 
129
  bool foundInvalid() const { return InvalidFound; }
 
130
 
 
131
private:
 
132
  SourceLocation CastLoc;
 
133
  const SourceManager &SM;
 
134
 
 
135
  bool Visited;
 
136
  bool CastFound;
 
137
  bool InvalidFound;
 
138
};
79
139
 
80
140
/// \brief Looks for implicit casts as well as sequences of 0 or more explicit
81
141
/// casts with an implicit null-to-pointer cast within.
90
150
/// ambiguities.
91
151
class CastSequenceVisitor : public RecursiveASTVisitor<CastSequenceVisitor> {
92
152
public:
93
 
  CastSequenceVisitor(tooling::Replacements &R, SourceManager &SM,
94
 
                      const LangOptions &LangOpts,
 
153
  CastSequenceVisitor(tooling::Replacements &R, ASTContext &Context,
95
154
                      const UserMacroNames &UserNullMacros,
96
155
                      unsigned &AcceptedChanges)
97
 
      : Replace(R), SM(SM), LangOpts(LangOpts), UserNullMacros(UserNullMacros),
98
 
        AcceptedChanges(AcceptedChanges), FirstSubExpr(0) {}
 
156
      : Replace(R), SM(Context.getSourceManager()), Context(Context),
 
157
        UserNullMacros(UserNullMacros), AcceptedChanges(AcceptedChanges),
 
158
        FirstSubExpr(0), PruneSubtree(false) {}
 
159
 
 
160
  bool TraverseStmt(Stmt *S) {
 
161
    // Stop traversing down the tree if requested.
 
162
    if (PruneSubtree) {
 
163
      PruneSubtree = false;
 
164
      return true;
 
165
    }
 
166
    return RecursiveASTVisitor<CastSequenceVisitor>::TraverseStmt(S);
 
167
  }
99
168
 
100
169
  // Only VisitStmt is overridden as we shouldn't find other base AST types
101
170
  // within a cast expression.
102
171
  bool VisitStmt(Stmt *S) {
103
172
    CastExpr *C = dyn_cast<CastExpr>(S);
104
173
    if (!C) {
105
 
      ResetFirstSubExpr();
 
174
      FirstSubExpr = 0;
106
175
      return true;
107
176
    } else if (!FirstSubExpr) {
108
 
        FirstSubExpr = C->getSubExpr()->IgnoreParens();
 
177
      FirstSubExpr = C->getSubExpr()->IgnoreParens();
109
178
    }
110
179
 
111
180
    if (C->getCastKind() == CK_NullToPointer ||
114
183
      SourceLocation StartLoc = FirstSubExpr->getLocStart();
115
184
      SourceLocation EndLoc = FirstSubExpr->getLocEnd();
116
185
 
117
 
      // If the start/end location is a macro argument expansion, get the
118
 
      // expansion location. If its a macro body expansion, check to see if its
119
 
      // coming from a macro called NULL.
 
186
      // If the location comes from a macro arg expansion, *all* uses of that
 
187
      // arg must be checked to result in NullTo(Member)Pointer casts.
 
188
      //
 
189
      // If the location comes from a macro body expansion, check to see if its
 
190
      // coming from one of the allowed 'NULL' macros.
120
191
      if (SM.isMacroArgExpansion(StartLoc) && SM.isMacroArgExpansion(EndLoc)) {
121
 
        StartLoc = SM.getFileLoc(StartLoc);
122
 
        EndLoc = SM.getFileLoc(EndLoc);
123
 
      } else if (SM.isMacroBodyExpansion(StartLoc) &&
124
 
                 SM.isMacroBodyExpansion(EndLoc)) {
 
192
        SourceLocation FileLocStart = SM.getFileLoc(StartLoc),
 
193
                       FileLocEnd = SM.getFileLoc(EndLoc);
 
194
        if (isReplaceableRange(FileLocStart, FileLocEnd, SM) &&
 
195
            allArgUsesValid(C)) {
 
196
          ReplaceWithNullptr(Replace, SM, FileLocStart, FileLocEnd);
 
197
          ++AcceptedChanges;
 
198
        }
 
199
        return skipSubTree();
 
200
      }
 
201
 
 
202
      if (SM.isMacroBodyExpansion(StartLoc) &&
 
203
          SM.isMacroBodyExpansion(EndLoc)) {
125
204
        llvm::StringRef OutermostMacroName =
126
 
            GetOutermostMacroName(StartLoc, SM, LangOpts);
 
205
            GetOutermostMacroName(StartLoc, SM, Context.getLangOpts());
127
206
 
128
207
        // Check to see if the user wants to replace the macro being expanded.
129
 
        bool ReplaceNullMacro =
130
 
            std::find(UserNullMacros.begin(), UserNullMacros.end(),
131
 
                      OutermostMacroName) != UserNullMacros.end();
132
 
 
133
 
        if (!ReplaceNullMacro)
134
 
          return false;
 
208
        if (std::find(UserNullMacros.begin(), UserNullMacros.end(),
 
209
                      OutermostMacroName) == UserNullMacros.end()) {
 
210
          return skipSubTree();
 
211
        }
135
212
 
136
213
        StartLoc = SM.getFileLoc(StartLoc);
137
214
        EndLoc = SM.getFileLoc(EndLoc);
138
215
      }
139
216
 
140
 
      AcceptedChanges +=
141
 
          ReplaceWithNullptr(Replace, SM, StartLoc, EndLoc) ? 1 : 0;
 
217
      if (!isReplaceableRange(StartLoc, EndLoc, SM)) {
 
218
        return skipSubTree();
 
219
      }
 
220
      ReplaceWithNullptr(Replace, SM, StartLoc, EndLoc);
 
221
      ++AcceptedChanges;
142
222
 
143
 
      ResetFirstSubExpr();
144
 
    }
 
223
      return skipSubTree();
 
224
    } // If NullTo(Member)Pointer cast.
145
225
 
146
226
    return true;
147
227
  }
148
228
 
149
229
private:
150
 
  void ResetFirstSubExpr() { FirstSubExpr = 0; }
 
230
  bool skipSubTree() { PruneSubtree = true; return true; }
 
231
 
 
232
  /// \brief Tests that all expansions of a macro arg, one of which expands to
 
233
  /// result in \p CE, yield NullTo(Member)Pointer casts.
 
234
  bool allArgUsesValid(const CastExpr *CE) {
 
235
    SourceLocation CastLoc = CE->getLocStart();
 
236
 
 
237
    // Step 1: Get location of macro arg and location of the macro the arg was
 
238
    // provided to.
 
239
    SourceLocation ArgLoc, MacroLoc;
 
240
    if (!getMacroAndArgLocations(CastLoc, ArgLoc, MacroLoc))
 
241
      return false;
 
242
 
 
243
    // Step 2: Find the first ancestor that doesn't expand from this macro.
 
244
    ast_type_traits::DynTypedNode ContainingAncestor;
 
245
    if (!findContainingAncestor(
 
246
            ast_type_traits::DynTypedNode::create<Stmt>(*CE), MacroLoc,
 
247
            ContainingAncestor))
 
248
      return false;
 
249
 
 
250
    // Step 3:
 
251
    // Visit children of this containing parent looking for the least-descended
 
252
    // nodes of the containing parent which are macro arg expansions that expand
 
253
    // from the given arg location.
 
254
    // Visitor needs: arg loc
 
255
    MacroArgUsageVisitor ArgUsageVisitor(SM.getFileLoc(CastLoc), SM);
 
256
    if (const Decl *D = ContainingAncestor.get<Decl>())
 
257
      ArgUsageVisitor.TraverseDecl(const_cast<Decl *>(D));
 
258
    else if (const Stmt *S = ContainingAncestor.get<Stmt>())
 
259
      ArgUsageVisitor.TraverseStmt(const_cast<Stmt *>(S));
 
260
    else
 
261
      llvm_unreachable("Unhandled ContainingAncestor node type");
 
262
 
 
263
    if (ArgUsageVisitor.foundInvalid())
 
264
      return false;
 
265
 
 
266
    return true;
 
267
  }
 
268
 
 
269
  /// \brief Given the SourceLocation for a macro arg expansion, finds the
 
270
  /// non-macro SourceLocation of the macro the arg was passed to and the
 
271
  /// non-macro SourceLocation of the argument in the arg list to that macro.
 
272
  /// These results are returned via \c MacroLoc and \c ArgLoc respectively.
 
273
  /// These values are undefined if the return value is false.
 
274
  ///
 
275
  /// \returns false if one of the returned SourceLocations would be a
 
276
  /// SourceLocation pointing within the definition of another macro.
 
277
  bool getMacroAndArgLocations(SourceLocation Loc, SourceLocation &ArgLoc,
 
278
                               SourceLocation &MacroLoc) {
 
279
    assert(Loc.isMacroID() && "Only reasonble to call this on macros");
 
280
 
 
281
    ArgLoc = Loc;
 
282
 
 
283
    // Find the location of the immediate macro expansion.
 
284
    while (1) {
 
285
      std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(ArgLoc);
 
286
      const SrcMgr::SLocEntry *E = &SM.getSLocEntry(LocInfo.first);
 
287
      const SrcMgr::ExpansionInfo &Expansion = E->getExpansion();
 
288
 
 
289
      SourceLocation OldArgLoc = ArgLoc;
 
290
      ArgLoc = Expansion.getExpansionLocStart();
 
291
      if (!Expansion.isMacroArgExpansion()) {
 
292
        if (!MacroLoc.isFileID())
 
293
          return false;
 
294
 
 
295
        StringRef Name =
 
296
            Lexer::getImmediateMacroName(OldArgLoc, SM, Context.getLangOpts());
 
297
        return std::find(UserNullMacros.begin(), UserNullMacros.end(), Name) !=
 
298
               UserNullMacros.end();
 
299
      }
 
300
 
 
301
      MacroLoc = SM.getImmediateExpansionRange(ArgLoc).first;
 
302
 
 
303
      ArgLoc = Expansion.getSpellingLoc().getLocWithOffset(LocInfo.second);
 
304
      if (ArgLoc.isFileID())
 
305
        return true;
 
306
 
 
307
      // If spelling location resides in the same FileID as macro expansion
 
308
      // location, it means there is no inner macro.
 
309
      FileID MacroFID = SM.getFileID(MacroLoc);
 
310
      if (SM.isInFileID(ArgLoc, MacroFID))
 
311
        // Don't transform this case. If the characters that caused the
 
312
        // null-conversion come from within a macro, they can't be changed.
 
313
        return false;
 
314
    }
 
315
 
 
316
    llvm_unreachable("getMacroAndArgLocations");
 
317
  }
 
318
 
 
319
  /// \brief Tests if TestMacroLoc is found while recursively unravelling
 
320
  /// expansions starting at TestLoc. TestMacroLoc.isFileID() must be true.
 
321
  /// Implementation is very similar to getMacroAndArgLocations() except in this
 
322
  /// case, it's not assumed that TestLoc is expanded from a macro argument.
 
323
  /// While unravelling expansions macro arguments are handled as with
 
324
  /// getMacroAndArgLocations() but in this function macro body expansions are
 
325
  /// also handled.
 
326
  ///
 
327
  /// False means either:
 
328
  /// - TestLoc is not from a macro expansion
 
329
  /// - TestLoc is from a different macro expansion
 
330
  bool expandsFrom(SourceLocation TestLoc, SourceLocation TestMacroLoc) {
 
331
    if (TestLoc.isFileID()) {
 
332
      return false;
 
333
    }
 
334
 
 
335
    SourceLocation Loc = TestLoc, MacroLoc;
 
336
 
 
337
    while (1) {
 
338
      std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(Loc);
 
339
      const SrcMgr::SLocEntry *E = &SM.getSLocEntry(LocInfo.first);
 
340
      const SrcMgr::ExpansionInfo &Expansion = E->getExpansion();
 
341
 
 
342
      Loc = Expansion.getExpansionLocStart();
 
343
 
 
344
      if (!Expansion.isMacroArgExpansion()) {
 
345
        if (Loc.isFileID()) {
 
346
          if (Loc == TestMacroLoc)
 
347
            // Match made.
 
348
            return true;
 
349
          return false;
 
350
        }
 
351
        // Since Loc is still a macro ID and it's not an argument expansion, we
 
352
        // don't need to do the work of handling an argument expansion. Simply
 
353
        // keep recursively expanding until we hit a FileID or a macro arg
 
354
        // expansion or a macro arg expansion.
 
355
        continue;
 
356
      }
 
357
 
 
358
      MacroLoc = SM.getImmediateExpansionRange(Loc).first;
 
359
      if (MacroLoc.isFileID() && MacroLoc == TestMacroLoc)
 
360
        // Match made.
 
361
        return true;
 
362
 
 
363
      Loc = Expansion.getSpellingLoc();
 
364
      Loc = Expansion.getSpellingLoc().getLocWithOffset(LocInfo.second);
 
365
      if (Loc.isFileID())
 
366
        // If we made it this far without finding a match, there is no match to
 
367
        // be made.
 
368
        return false;
 
369
    }
 
370
 
 
371
    llvm_unreachable("expandsFrom");
 
372
  }
 
373
 
 
374
  /// \brief Given a starting point \c Start in the AST, find an ancestor that
 
375
  /// doesn't expand from the macro called at file location \c MacroLoc.
 
376
  ///
 
377
  /// \pre MacroLoc.isFileID()
 
378
  /// \returns true if such an ancestor was found, false otherwise.
 
379
  bool findContainingAncestor(ast_type_traits::DynTypedNode Start,
 
380
                              SourceLocation MacroLoc,
 
381
                              ast_type_traits::DynTypedNode &Result) {
 
382
    // Below we're only following the first parent back up the AST. This should
 
383
    // be fine since for the statements we care about there should only be one
 
384
    // parent as far up as we care. If this assumption doesn't hold, need to
 
385
    // revisit what to do here.
 
386
 
 
387
    assert(MacroLoc.isFileID());
 
388
 
 
389
    do {
 
390
      ASTContext::ParentVector Parents = Context.getParents(Start);
 
391
      if (Parents.empty())
 
392
        return false;
 
393
      assert(Parents.size() == 1 &&
 
394
             "Found an ancestor with more than one parent!");
 
395
 
 
396
      ASTContext::ParentVector::const_iterator I = Parents.begin();
 
397
 
 
398
      SourceLocation Loc;
 
399
      if (const Decl *D = I->get<Decl>())
 
400
        Loc = D->getLocStart();
 
401
      else if (const Stmt *S = I->get<Stmt>())
 
402
        Loc = S->getLocStart();
 
403
      else
 
404
        llvm_unreachable("Expected to find Decl or Stmt containing ancestor");
 
405
 
 
406
      if (!expandsFrom(Loc, MacroLoc)) {
 
407
        Result = *I;
 
408
        return true;
 
409
      }
 
410
      Start = *I;
 
411
    } while (1);
 
412
 
 
413
    llvm_unreachable("findContainingAncestor");
 
414
  }
151
415
 
152
416
private:
153
417
  tooling::Replacements &Replace;
154
418
  SourceManager &SM;
155
 
  const LangOptions &LangOpts;
 
419
  ASTContext &Context;
156
420
  const UserMacroNames &UserNullMacros;
157
421
  unsigned &AcceptedChanges;
158
422
  Expr *FirstSubExpr;
 
423
  bool PruneSubtree;
159
424
};
 
425
} // namespace
160
426
 
161
427
NullptrFixer::NullptrFixer(clang::tooling::Replacements &Replace,
162
428
                           unsigned &AcceptedChanges, RiskLevel)
169
435
}
170
436
 
171
437
void NullptrFixer::run(const ast_matchers::MatchFinder::MatchResult &Result) {
172
 
  SourceManager &SM = *Result.SourceManager;
173
 
 
174
438
  const CastExpr *NullCast = Result.Nodes.getNodeAs<CastExpr>(CastSequence);
175
439
  assert(NullCast && "Bad Callback. No node provided");
176
440
  // Given an implicit null-ptr cast or an explicit cast with an implicit
177
441
  // null-to-pointer cast within use CastSequenceVisitor to identify sequences
178
442
  // of explicit casts that can be converted into 'nullptr'.
179
 
  CastSequenceVisitor Visitor(Replace, SM, Result.Context->getLangOpts(),
180
 
     UserNullMacros, AcceptedChanges);
 
443
  CastSequenceVisitor Visitor(Replace, *Result.Context, UserNullMacros,
 
444
                              AcceptedChanges);
181
445
  Visitor.TraverseStmt(const_cast<CastExpr *>(NullCast));
182
446
}