ymandel added inline comments.
================ Comment at: clang/include/clang/Tooling/Refactoring/Transformer.h:70 +// +// * Explanation: explanation of the rewrite. +// ---------------- ilya-biryukov wrote: > ymandel wrote: > > ilya-biryukov wrote: > > > NIT: maybe mention what it should be used for? we plan to show to to the > > > user (e.g. in the clang-tidy fix description), right? > > Done. But, given that we don't use this field yet, I'm fine deleting it > > until a future revision. I'm also fine leaving it given that we know we'll > > be needing it later. > Up to you, to me it feels like the presence of this field defines what this > class is used for. > 1. If there's an explanation, it feels like it should represent a complete > fix or refactoring that could be presented to the user. > 2. Without an explanation, it might feel like something lower-level (e.g. one > could write a bunch of RewriteRule whose changes are later combined and > surfaced to the user as a full refactoring). > > Both approaches make sense, and I assume (1) is the desired abstraction this > class represents, so keeping the field looks ok. Agreed. Keeping it. ================ Comment at: clang/include/clang/Tooling/Refactoring/Transformer.h:89 +// \code +// RewriteRule R = buildRule(functionDecl(...)).replaceWith(...); +// \endcode ---------------- ilya-biryukov wrote: > ymandel wrote: > > ilya-biryukov wrote: > > > Could you also add examples on how to apply the rewrite rule here? > > > So that the users can have an idea about the full workflow when reading > > > the code. > > Is this what you had in mind? Unlike clang-tidy, there is no neat > > infrastructure into which we can drop it. > Yeah, exactly, but could we keep is a bit shorter by removing the pieces > which are non-relevant to the actual transformer usage. > Something like: > ``` > // To apply a rule to the clang AST, use Transformer class: > // \code > // AtomicChanges Changes; > // Transformer T( > // MyRule, [&Changes](const AtomicChange &C) { Changes.push_back(C); > };); > // ast_matchers::MatchFinder MatchFinder; > // T.registerMatchers(&MatchFinder); > // // ... insert code to run the ast matchers. > // // Consume the changes. > // applyAtomicChanges(..., Changes); > ``` > > Or just mention that `Transformer` class should be used to apply the rewrite > rule and obtain the corresponding replacements. went w/ the second suggestion. ================ Comment at: clang/include/clang/Tooling/Refactoring/Transformer.h:136 + + RewriteRule(ast_matchers::internal::DynTypedMatcher M) + : Matcher(initMatcher(M)), Target(RootId), TargetKind(M.getSupportedKind()), ---------------- ilya-biryukov wrote: > NIT: Maybe remove the constructor and let the builder handle this? > Technically, users can break the invariants after creating the rewrite rules > anyway, so having this constructor does not buy much in terms of safer coding > practices, but makes it harder to use `RewriteRule` as a plain struct > (specifically, having no default constructor might make it awkward). > > Up to you, of course. Agreed, but DynTypedMatcher has no default constructor, so we have to provide something. I dropped the constructor, but added an initializer to `Matcher` to enable the default constructor. ================ Comment at: clang/include/clang/Tooling/Refactoring/Transformer.h:184 +RewriteRuleBuilder buildRule(ast_matchers::internal::Matcher<T> M) { + return RewriteRuleBuilder(M); +} ---------------- ilya-biryukov wrote: > Isn't this overload redundant in presence of `buildRule(DynTypedMatcher)`? > Both seem to call into the constructor that accept a `DynTypedMatcher`, so > `Matcher<T>` is convertible to `DynTypedMatcher`, right?. I think I was avoiding some extra construction, but even if so, I can't see its worth the added complexity. thx ================ Comment at: clang/lib/Tooling/Refactoring/Transformer.cpp:133 + +namespace clang { +namespace tooling { ---------------- ilya-biryukov wrote: > ymandel wrote: > > ilya-biryukov wrote: > > > NIT: remove namespaces for consistency with the rest of the code. > > > > > > (Probably a leftover from the previous version) > > This is necessary as far as I can tell. W/o it, I get a linker failure > > (missing definition). Based on the declaration in the header, the compiler > > resolves the reference below to clang::tooling::applyRewriteRule() but this > > definition ends up in the global namespace. > > > > I think the using decls only work for method definitions -- the type seems > > to resolve to be the one in the namespace. But free functions don't get the > > same treatment. Unless I"m doing something wrong? > Yeah, you should explicitly qualify to let the compiler know the namespace of > a corresponding declaration: > ``` > Expected<Transformation> > clang::tooling::applyRewriteRule(...) { > // ... > } > ``` > > `tooling::applyRewriteRule` would also work since we have `using namespace > clang::tooling;` at the top of the file. ah... ================ Comment at: clang/lib/Tooling/Refactoring/Transformer.cpp:157 + isOriginMacroBody(*Match.SourceManager, Target.getBegin())) + return Transformation(); + ---------------- ilya-biryukov wrote: > ymandel wrote: > > ilya-biryukov wrote: > > > Why not return an error in case of macros too? Is there any use of the > > > empty transformation to the clients? > > > Alternatively, we might want to document this behavior (applyRewriteRule > > > can return empty transformations) and it's rationale. > > I think the common case is that we simply want to skip macros -- there's > > nothing erroneous about them, they're just usually hard to deal w/ > > correctly. That said, we might want to change this to *never* return an > > error and just assert when things go wrong. The advantage of the current > > design is that callers can in principle ignore failed rewrites. > > > > However, in practice, if the rewrite fails that means it had a bug, so it > > might be best to asssert(). Only real advantage, then, is that this is > > easier to test since it doesn't crash the program. > > > > WDYT? > The current approach LG, and we have the comments about those cases. > > I agree with you that handling macros is hard, so skipping them makes sense > for most rewrite rules one would write and at the same time, it'd be useful > to let the users of the code know that a rewrite rule could not be applied > because of macros. > Returning an empty transformation in that case seems like the best option, > the alternative that I can think is less nice: we could have a special error > for macros and make users `llvm::handleErrors` to figure out those cases. > This is clunky and the resulting code is not very nice. > > Agreed. If error handling was nicer, then I think that your suggestion would be ideal. ================ Comment at: clang/unittests/Tooling/TransformerTest.cpp:61 +)cc"; +} // namespace + ---------------- ilya-biryukov wrote: > ymandel wrote: > > ilya-biryukov wrote: > > > Maybe put the whole file into an anonymous namespace? > > > To avoid potential name clashes with other test files (and ODR violations > > > that might follow) > > also removed `static` qualifiers from functions since they are now > > redundant. > LG. > As a note, my colleagues mentioned that the LLVM Style Guide says one should > put 'static' even in that case, because it makes it easier for readers of the > code to spot the file-private functions (they don't need to look for an > enclosing anonymous namespace). > > I'm personally happy either with or without static. static sounds good to me. Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D59376/new/ https://reviews.llvm.org/D59376 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits