You can do this reliably with a program transformation system (PTS). These are IDE-independent.
One of these is our DMS Software Reengineering Toolkit. OP can accomplish his specific task with code something like the following DMS meta-program: (not tested and doesn't handle all the edge cases):
(= parse_Tree (Domains:Java:Parser:ParseFile (. "path/to/.java")))
(local (= [method_tree AST:Node] (AST:ScanTree parse_Tree (Registry:Pattern (. `any_method'))
(ifthen (&& (~= method_tree AST:NullTree)
(Registry:PatternMatch method_tree (. `TestClass'))
(~= AST:NullTree (AST:ScanTree method_tree
(Registry:Pattern (. `abcdef_identifier'))))
(Registry:ApplyTransform method_tree (. `insert_MyAnnotation'))
)ifthen
)local
(Registry:PrettyPrintToFile method_tree (. "path/to/.java"))
DMS's metaprogramming language looks like Lisp, with prefix operators. (Get over it :-)
ParseFile reads a source file and builds an AST, parked in parse_Tree.
ScanTree scans tree looking for a point where the supplied predicate ("Registry:Pattern (. `any_method'") is true, and returns a matching subtree or null.
Registry:PatternMatch checks that a pattern predicate is true at the root of the specified tree. Registry:ApplyTransform applies a source-to-source transformation to modify the tree.
This metaprogram is supported by a set of named patterns, which make it easy to express tests/transforms on tree without knowing every last detail of the tree structure.
These are oversimplified for presentation purposes:
default domain Java~v7;
pattern any_method(p: path_to_name, name: method_name, args: arguments,
b: body, a: annotations):declaration =
" \p \name(\args) \a \b "; -- doesn't handle non-functions but easily adjusted
pattern TestClass(p: path_to_name, name: method_name, args: arguments,
b: body, a: annotations):declaration =
" \p \name(\args) [Test.class] \b ";
pattern abcdef_identifier():IDENTIFIER =
"abcdef";
rule insert_MyAnnotation(p: path_to_name, name: method_name, args: arguments,
b: body, a: annotations):declaration =
" \p \name(\args) \a \b "
->
" \p \name(\args) \a [myAnnotation] \b ";
The quote marks are metaquotes; they delineate the boundaries between the syntax of the pattern matching language as a whole, and code fragments written in the target language (in this case, Java, because of the domain declaration). Inside the meta quotes is target (Java) language syntax, with escaped identifiers representing pattern variables that correspond to specific tree node types. You have to know the rough structure of the grammar to write these, but notice we didn't really dive into details of how annotations or anything is formed.
Arguably the "any_method" and "TestClass" patterns could be folded into one (in fact, just the TestClass pattern itself, since it is pure specialization of "any_method".
The last rule (the others are patterns, only meant for matching) says, "if you see X, replace it by Y". What the specific rule does is pattern match to the method with some list of annotations, and add another one.
This is the way to reliable program transformations. If you don't want to use DMS (a commercial product), check out the Wikipedia page for alternatives.