ymandel added a comment.

Thanks for the detailed review and really helpful comments!



================
Comment at: clang/include/clang/Tooling/Refactoring/Transformer.h:38
+/// @{
+using ast_matchers::CXXCtorInitializerMatcher;
+using ast_matchers::DeclarationMatcher;
----------------
ilya-biryukov wrote:
> I'm not sure if this is in the LLVM style guide, but we might want to avoid 
> introducing these names into `clang::tooling` namespaces in the headers.
> 
> My fear is that users will rely on those using without knowing that 
> explicitly and won't add corresponding `using` directives or qualifiers to 
> their `.cpp` files, making refactoring and moving the code around harder.
> 
> Could you fully-qualify those names in the header instead? There does not 
> seem to be too many of them.
right. I'd intended to introduce these into the clang tooling namespace -- that 
is, these weren't just convenience aliases for the header file. But, I no 
longer think that's useful in any case, so dropping them is certainly best.


================
Comment at: clang/include/clang/Tooling/Refactoring/Transformer.h:65
+
+using TextGenerator = std::function<llvm::Expected<std::string>(
+    const ast_matchers::MatchFinder::MatchResult &)>;
----------------
ilya-biryukov wrote:
> Why would a `TextGenerator`  fail?
> I imagine all of the failure cases are programming errors (matchers in the 
> rewrite rule were not aligned with the corresponding text generating 
> function). For those cases, using the `assert` macro seems cleaner.
Sure.  I could go either way. I think some of these cases fall on the border 
between an invariant violation and "invalid argument" or some such.  But, let's 
keep it simpler for now.


================
Comment at: clang/include/clang/Tooling/Refactoring/Transformer.h:116
+  // never be the empty string.
+  std::string Target = RootId;
+  ast_type_traits::ASTNodeKind TargetKind;
----------------
ilya-biryukov wrote:
> NIT: maybe move all inits to the constructor?
> To have all initializers in one place.
nicer, thanks.


================
Comment at: clang/include/clang/Tooling/Refactoring/Transformer.h:170
+
+  RewriteRuleBuilder(const RewriteRuleBuilder &) = default;
+  RewriteRuleBuilder(RewriteRuleBuilder &&) = default;
----------------
ilya-biryukov wrote:
> NIT: maybe remove the `=default` copy and move ctors and assignments?
> They should be generated automatically anyway, right?
Sure. I was going based on google's style recommendations, but personally i 
prefer leaving them implicit.


================
Comment at: clang/lib/Tooling/Refactoring/Transformer.cpp:28
+
+namespace clang {
+namespace tooling {
----------------
ilya-biryukov wrote:
> Other files in the tooling library seem to be adding `using namespace clang` 
> instead of putting the declaration into a namespace.
> Could you please change the new code to do the same for consistency?
> 
Done.  Agreed about being consistent. FWIW, I can't say I like this style.  
Perhaps because I'm not used to it, but it feels too implicit.  It forces the 
reader to figure out where each definition is being associated. Also, I 
discovered it only works for method definitions. Free functions still need to 
be explicitly namespaced.

Any idea what the reason for this style is?


================
Comment at: clang/lib/Tooling/Refactoring/Transformer.cpp:30
+namespace tooling {
+namespace {
+using ::clang::ast_matchers::MatchFinder;
----------------
ilya-biryukov wrote:
> Why put using directives into an anonymous namespace?
> I have not seen this pattern before, could you point me to explanations on 
> why this is useful?
You gain an extra little bit of robustness against clashing with something 
declared in the enclosing namespace.  But, this is overkill even for me -- I 
generally only do this when I already have an anonymous namespace; there's no 
good reason to create one for this purpose.


================
Comment at: clang/lib/Tooling/Refactoring/Transformer.cpp:111
+// Requires verifyTarget(node, target_part) == success.
+static CharSourceRange getTarget(const DynTypedNode &Node, ASTNodeKind Kind,
+                                 NodePart TargetPart, ASTContext &Context) {
----------------
ilya-biryukov wrote:
> NIT: consider merging `verifyTarget` into `getTarget` and making `getTarget` 
> return `Expected<CharSourceRange>`.
> Would allow avoiding to write one of the complicated switches and 
> error-checking arguably looks just as natural in the `getTarget` as it is in 
> `verifyTarget`.
> 
> Also, having the invariants closer to the code using them makes it easier to 
> certify both are correct, e.g. seeing that `NamedDecl.isIdentifier()` was 
> checked before accessing the `NamedDecl.getName()` in the same function is 
> simpler.
Yes, I like it much better this way.  The split wasn't worth it.


================
Comment at: clang/lib/Tooling/Refactoring/Transformer.cpp:134
+      auto R = CharSourceRange::getTokenRange(TokenLoc, TokenLoc);
+      // Verify that the range covers exactly the name. FIXME: extend this code
+      // to support cases like `operator +` or `foo<int>` for which this range
----------------
ilya-biryukov wrote:
> NIT: start a fixme at a new line to make it more visible.
> Or is it `clang-format` merging it into the previous line?
> 
Done.
It's emacs (c-fill-paragraph), clang-format is better about this, because it's 
very conservative about touching comments.


================
Comment at: clang/lib/Tooling/Refactoring/Transformer.cpp:144
+    if (const auto *E = Node.get<clang::DeclRefExpr>()) {
+      TokenLoc = E->getLocation();
+      break;
----------------
ilya-biryukov wrote:
> This could be `operator+` too, right?
> ```
> struct X {
>   X operator+(int);
> 
>   void test() {
>     X (X::*ptr)(int) = &X::operator+;
>   }
> };
> ```
> 
> Would probably want to bail out in this case as well.
The check `E->getNameInfo().getName().isIdentifier()` rules that out.  It was 
hidden in `verifyTarget()`. I hope the new code makes this clearer?
Also, I updated the test `TransformerTest.NodePartNameDeclRefFailure` to cover 
this case.


================
Comment at: clang/lib/Tooling/Refactoring/Transformer.cpp:160
+                                          const MatchResult &Result) {
+  // Ignore results in failing TUs or those rejected by the where clause.
+  if (Result.Context->getDiagnostics().hasErrorOccurred())
----------------
ilya-biryukov wrote:
> The comment still mentions the where clause. A leftover from the previous 
> version?
right. deleted the comment altogether.


================
Comment at: clang/lib/Tooling/Refactoring/Transformer.cpp:199
+
+// `Explanation` is a `string&`, rather than a `string` or `StringRef` to save
+// an extra copy needed to intialize the captured lambda variable.  After 
C++14,
----------------
ilya-biryukov wrote:
> Maybe use `std::string` in the public interface anyway? 
> - This function is definitely not a bottleneck, so an extra copy is not a big 
> deal for performance.
> - Using `std::string` would let the clients save a copy in their client code 
> if they can (by using `std::move` or creating an r-value string in the first 
> place).
> - We will have a copy in the body of our function (we have it anyway). We'll 
> eliminate it after switching to C++14 in the body of our function without 
> changing the clients.
Agreed. Updated all relevant places.


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

Reply via email to