I'm a beginner to C++, attempting to lint Objective-C code with clang. I understand that macros are first expanded before nodes and properties are visited with AST.
I have a macro named NIL_CHECK, which is used in numerous files. While performing the lint, I would like to skip the variable declaration of the line where this macro is expanded/used.
For instance, the first line in this example should be linted, while the second line needs to be skipped such that false positives are not thrown when there's a macro expansion:
// Must be checked
NSDictionary *playerParams = #{ #"videoId" : videoId, #"playerVars" : playerVars };
// Must be skipped since there's a macro
PlayerProfile *const playerProfile = [[PlayerProfile alloc] initWithData:NIL_CHECK(playerParams)];
Here is the VisitVarDecl visitor method, which traverses through each variable declaration to perform appropriate lint checks:
bool VisitVarDecl(VarDecl *node) {
if (isCollectionType(node -> getType()) && !hasTypeArguments(node -> getType())) {
addViolation(node, this, description(node -> getNameAsString()));
}
return true;
}
How can I determine macros and skip such variable declarations?
Here is a nice answer by Valeriy, I think it covers what you want to achieve.
To summarise:
You want to find the string NIL_CHECK inside a VarDecl, which has already been expanded when you visit the AST. The original text in your source code can be obtained with the help of Lexer. You can use the location of the full varDecl expr or only the macro-contained part. Then the macro name can be detected from the string returned by getSourceText of the Lexer .
Related
I have a config file for disabling specific code paths. I just added a bool option to the yaml file, and am having a hard time figuring out how yaml-cpp handles those. The documentation is a bit lighter than preferred, and I don't see anything for a Node that fits my use case. I could manually parse for the strings returned as true and false, but that seems like something the framework should support, as there are multiple styles of writing trueand false in the spec. Is there any means of getting a bool value out of yaml-cpp?
IsScalarwas the closest I could find.
void LoadConfig(string file)
{
Node config = LoadFile(file);
string targetDirectory;
bool compile;
if (config["TargetDirectory"])
targetDirectory = config["TargetDirectory"].Scalar();
if (config["Compile"])
compile = Config["Compile"].IsScalar();
}
You want the template as() method:
config["Compile"].as<bool>()
Or a neater way to do it all in one line instead of three using a default value (which also addresses your potential uninitialized variable bug):
bool compile = config["Compile"].as<bool>(false);
I'm using version of 0.66.1 of uncrustify, and am puzzled by the behavior of 'mod_full_brace_if' which I've set to 'force'. Its comment says:
Add or remove braces on single-line 'if' statement. Will not remove the braces if they contain an 'else'.
Given the line:
if (flag) val = 10;
I hoped/expected it to be transformed to
if (flag) { val = 10; }
Instead it remains unchanged.
Is this just my misunderstanding of the behavior of 'mod_full_brace_if'?
Later:
I had some time to do a little experimentation at home. I started off by creating a new format file, and modified some of the settings having to do with forcing braces to be on the same line as various keywords, as well as some settings forcing braces to surround a one-line body. I made a test file with the following contents:
void foo() {
bool flag;
int var;
if (flag) var = 10;
if (!flag)
var = 20;
}
Running uncrustify with my new config file yielded the same lack of transformation that I saw at work.
I then created another config file and only changed 'mod_full_brace_if' (to 'force'). Using it on my test file resulted in braces surrounding the bodies of the if statements. Clearly there's some weird interaction of multiple settings. I see some change-a-setting-and-test drudgery in my future.
It turns out that the problem was setting "mod_full_brace_if_chain" to "true".
The documentation says:
Make all if/elseif/else statements in a chain be braced or not. Overrides mod_full_brace_if.
If any must be braced, they are all braced. If all can be unbraced, then the braces are removed.
I didn't read the last sentence closely enough when setting the value.
I've joined an existing project and I'm the first team member to use clang-format. The existing style mostly matches except for a couple of annoying differences. Here's one (the other one being here):
folly::dynamic makeRequest(const string &response) {
return folly::dynamic::object()
("log_type", "FOO")
("src_id", "42")
("dst_id", "666")
("success", true);
}
clang-format insists on formatting it like this:
folly::dynamic makeRequest(const string &token_response) {
// using longer variable names to highlight using up the whole line lenght
return folly::dynamic::object()("log_type", "FOO")(
"src_id", somethingId)("dst_id", whateverId)("success",
sucess);
}
In the former style I don't feel strongly for how continuation lines are indented, as long as we get one method invocation per line. Is that possible?
Not the best possible solution, but you can force line breaks by putting "//" after each line:
return folly::dynamic::object() //
("log_type", "FOO") //
("src_id", "42") //
("dst_id", "666") //
("success", true);
Another approach that I have used myself is to turn off clang-format for the specific block of code.
// clang-format off
return folly::dynamic::object()
("log_type", "FOO")
("src_id", "42")
("dst_id", "666")
("success", true)
;
// clang-format on
This might not be optimal if you have more complicated logic inside the chained method params (since you will want that logic to be formatted), but if you just have a tuple like this it can be cleaner than adding empty comments.
Both ways you are bypassing clang-format, but this way is cleaner (imo) and signifies your intentions more clearly to future developers.
I defined a macro in a module, and it works fine.
Now, I'm trying to document said macro with an example. Apparently, I need to manually specify the crate line to ask for macros:
/// ```
/// # #[macro_use] extern crate foo;
/// // Some code
/// ```
However, I now get an error saying:
error: an `extern crate` loading macros must be at the crate root
Apparently the example code is loaded in the macro's module, and does not seem compatible with macro_use...
I can't believe everyone writes macros directly in the root module... right?
Well adding a main function did the trick. My example code did not need to run anything (just compile) so I didn't even bother adding a main function, but apparently adding it puts the code in a virtual "crate root", and it accepts the macro_use. Yay!
So what I did is just add :
/// # fn main() { }
I am new to lisp and I am having trouble figuring out how to create a macro in emacs with the following functionality: Say I am tired of writing out the pattern in c++ for a for loop:
for (int i = 0; i < N; i++) {
}
Call this macro "forloop" then I would like to do the following: when I type "M-x forloop" the macro prints out
for (int
in the buffer and waits for an input. Then I type "i" and hit return after which the macro continues and prints
for (int i = 0; i <
And again waits for input. Finally after I type "N" and hit return the macro finishes by printing the rest:
for (int i = 0; i < N; i++) {
}
After some extensive reading and testing, I was able to write simple lisp functions, create my own macros, save them and call them and so on... but I still can't quite figure out how to make a macro that does something like I have described above. Any thoughts would be much appreciated! Thanks in advance!
Macros like this could be really nice for speeding up coding in any language. I would prefer the macro to be dynamic in the way described so that you don't have to remember how many arguments it needs and in which order they go when calling it.
I use yasnippet (http://www.emacswiki.org/emacs/Yasnippet) for this, but there are a lot of other solution.
In yasnippet you type a keyword for you snippet (say for) then the yasnippet key shortcut, then you have field to fill, using tab to go from one field to the next.
Every snippet is define in is own file in some easy to learn DSL.
I don't know anything better than yasnippet for this problem.
Here's the relevant snippet:
# -*- mode: snippet -*-
#name : for (...; ...; ...) { ... }
# --
for (unsigned int ${1:i}=0; $1<${2:N}; ++$1)$0
Note that there are two arguments (zero is the exit point),
both have default values, but you can change them by just typing.
key binding for yasnippet
I highly recommend to bind yas/expand to C-o, so it
doesn't conflict with auto-complete-mode.
The default binding for this shortcut is near-useless, but it's in
a great position:
(global-set-key "\C-o" 'aya-open-line)
(defun aya-open-line ()
(interactive)
(cond ((expand-abbrev))
((yas/snippets-at-point)
(yas/next-field-or-maybe-expand-1))
(((yas/expand)))))
This way, the shortcut for expanding and moving to the next field
is the same, which makes you very quick.
Also note that expand-abbrev takes precedence: you can fill
an abbrev table for c++-mode for the stuff that you use.
Abbrevs don't take an argument, but they all live in one table,
instead of each yasnippet living in its own file, so it's
very easy to edit abbrevs.
special function to insert curly braces
I wouldn't recommend putting the braces in yasnippet,
since sometimes you need them and sometimes you don't.
I use this function instead:
(defun ins-c++-curly ()
"Insert {}."
(interactive)
(if (looking-back "\\()\\|try\\|else\\|const\\|:\\)$")
(progn
(insert " {\n\n}")
(indent-according-to-mode)
(forward-line -1)
(indent-according-to-mode))
(insert "{}")
(backward-char))
You can see similar macros in sgml-mode.el, for example html-href-anchor, which inserts an HREF anchor (obviously :-).
You will get more specific answers if you tag this as [elisp].
If you are reading this and wondering exactly how to do what I requested with yasnippit, here is my yasnippit file:
# name: fori ... { ... }
# key: fori
# --
for (int ${1:intname} = 0; ${1:$(yas-substr text "[^: ]*")} < ${2:max}; ${1:$(yas-substr text "[^: ]*")}++) {
$0
}
Note that yasnippit already has a function for "for" in c++ mode, but I did not like the way it behaved.
Conclusion, yasnippit is awesome and super easy! Thanks for the suggestion!